package com.yangchuang.openpicture.controller;

import com.yangchuang.openpicture.communication.ResponseMessage;
import com.yangchuang.openpicture.communication.ResultCode;
import com.yangchuang.openpicture.constant.FileSizeConstants;
import com.yangchuang.openpicture.constant.FileUploadConstants;
import com.yangchuang.openpicture.constant.UserActionType;
import com.yangchuang.openpicture.dto.ImageOperationDTO;
import com.yangchuang.openpicture.dto.UploadImgaeDTO;
import com.yangchuang.openpicture.exception.BussinessException;
import com.yangchuang.openpicture.service.OSSService;
import com.yangchuang.openpicture.service.PictureService;
import com.yangchuang.openpicture.service.PictureStatisticsService;
import com.yangchuang.openpicture.service.UserStatisticsService;
import com.yangchuang.openpicture.util.ImageDimensionUtils;
import com.yangchuang.openpicture.vo.AiPictureInfo;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.List;


/**
 * 图片资源控制器 (已适配公共读OSS Bucket模式)
 */
@RestController
@RequestMapping("/picture")
@RequiredArgsConstructor
@Slf4j
public class PictureController {

    private final OSSService ossService;
    private final PictureService pictureService;
    private final PictureStatisticsService pictureStatisticsService;
    private final UserStatisticsService userStatisticsService;

    /**
     * 上传图片接口
     * 文件上传后，会立即返回其永久的公开访问URL。
     */
    @PostMapping("/upload")
    @Operation(summary = "上传图片（单个文件）", description = "上传单个图片文件及元数据")
    public ResponseMessage<Void> upload(@RequestPart("file") MultipartFile file, @Valid @RequestPart("data") UploadImgaeDTO uploadImageDTO) {
        log.info("【图片上传】开始处理用户上传请求，请求元数据：分类ID={}，图片名称={}，标签={}", uploadImageDTO.getCategoryId(), uploadImageDTO.getPictureName(), uploadImageDTO.getTags());
        try {
            // 1. 基础参数校验（补充文件名校验）
            log.info("【图片上传-校验阶段】开始基础参数校验，文件名：{}", file.getOriginalFilename());
            if (file.isEmpty()) {
                log.warn("【图片上传-校验失败】文件为空，触发业务异常：{}", ResultCode.EMPTY_PICTURE.getMessage());
                throw new BussinessException(ResultCode.EMPTY_PICTURE);
            }
            String originalFilename = file.getOriginalFilename();

            // 2. 缓存文件字节（关键：在OSS上传前先读取流，避免流被消耗）
            log.info("【图片上传-预处理】开始缓存文件字节数组，避免流重复读取问题");
            byte[] fileBytes = file.getBytes();
            long fileSize = fileBytes.length;  // 从缓存的字节数组获取大小，更准确
            log.info("【图片上传-预处理完成】文件字节缓存成功，实际文件大小={}KB", fileSize / 1024);
            // 3. 检查图片大小
            log.info("【图片上传-大小校验】开始校验文件大小，当前文件大小={}KB，最大允许大小={}KB", fileSize / 1024, FileSizeConstants.SINGLE_FILE_MAX_SIZE / 1024);
            if (fileSize > FileSizeConstants.SINGLE_FILE_MAX_SIZE) {
                log.warn("【图片上传-大小校验失败】文件超出最大限制，当前大小={}KB，触发业务异常：{}", fileSize / 1024, ResultCode.TOO_LARGE_FILE.getMessage());
                throw new BussinessException(ResultCode.TOO_LARGE_FILE);
            }

            log.info("【图片上传-大小校验通过】文件大小符合要求【图片上传-大小校验通过】文件大小符合要求");

            // 6. 后续处理（使用缓存的字节数组，避免读取已关闭的流）
            // 7  获取宽高
            int[] dimensions = ImageDimensionUtils.getDimensions(fileBytes);
            int width = dimensions[0];
            int height = dimensions[1];
            log.info("【图片上传-属性提取完成】图片宽高：{}x{}px", width, height);


            // 4. 上传文件到OSS（此时OSS内部会读取file的流，已提前缓存字节数组不影响后续操作）
            String objectName = ossService.uploadFile(file, FileUploadConstants.IMAGE);
            // 5. 生成永久访问URL
            String publicUrl = ossService.getSignedUrlByObjectName(objectName);
            if (!StringUtils.hasText(publicUrl)) {
                log.error("【图片上传-URL生成失败】URL为空，OSS对象名：{}，触发业务异常：{}", objectName, ResultCode.FILE_URL_GENERATE_FAILED.getMessage());
                throw new BussinessException(ResultCode.FILE_URL_GENERATE_FAILED);
            }
            log.info("【图片上传-URL生成成功】永久访问URL：{}", publicUrl);

            Long pictureId = pictureService.insertPicture(fileSize, publicUrl, uploadImageDTO.getCategoryId(), uploadImageDTO.getPictureName(), uploadImageDTO.getDescription(), uploadImageDTO.getTags(), width, height);
            log.info("【图片上传-数据入库成功】图片信息入库完成，数据库ID：{}", pictureId);
            // 9. 用户上传图片 不需要返回结果
            log.info("【图片上传-流程结束】整个上传流程完成，返回空结果，数据库ID：{}", pictureId);
            return ResponseMessage.success(null);
        } catch (Exception e) {
            log.error("【图片上传-未知异常】流程发生未捕获异常，文件名：{}，异常信息：{}", file.getOriginalFilename(), e.getMessage(), e);
            throw new BussinessException(ResultCode.INTERNAL_ERROR);
        }
    }

    /**
     * 操作选中的图片 可以是一张 也可以是多张 支持的操作类型:
     * 删除 数据库中逻辑删除  还需要涉及：
     * 图片统计表 删除的话 就把这些图片的数据同步进行逻辑删除了
     * 用户统计表 用户自己把某张图片删除了 这张图片对应的点赞数 浏览量等等就不算在用户的统计数据中了
     * 评论表 用户把某些图片删除 这张图片对应的评论 需要删除吗？？ 可以执行逻辑删除  也可以不执行 留作日后维权（可能）使用
     * 设为私密 外人看不见 更新图片数据库中的字段
     * 重新开放 外人看不见 更新图片数据库中的字段
     * 设为私密 和 重新开放 不隐藏任何统计表 因为在用户看来图片还存在呢
     */
    @DeleteMapping("/delete")
    @Operation(summary = "删除单个图片", description = "根据前端传来的图片的url,从数据库中删除指定图片。")
    public ResponseMessage<Void> delete(@Valid @RequestBody ImageOperationDTO imageDeleteDTO) {
        //用户删除/隐藏 自己上传的图片 逻辑 数据库中对应的图片 逻辑删除/设置隐藏 oss中的数据不删除

        //判断操作类型
        String actionType = imageDeleteDTO.getActionType();
        List<String> publicUrlS = imageDeleteDTO.getPublicUrlS();
        if (actionType.equals(UserActionType.DELETE)) {
            pictureService.batchdelete(publicUrlS);
            //图片统计表 进行逻辑删除 但是可能最新的数据还在redis中 删除图片统计表 然后redis同步的时候 判断下是否被逻辑删除？
            //或者去redis里面把这张图片的数据也删了
            //用户个人统计表 可以直接删除 即使比较新的数据 还在redis中
        } else if (actionType.equals(UserActionType.HIDE)) {
            pictureService.batchhide(publicUrlS);
        } else if (actionType.equals(UserActionType.REOPEN)) {
            pictureService.batchopen(publicUrlS);
        } else {
            throw new BussinessException(ResultCode.WRONG_OPERATION_TYPE);
        }
        return ResponseMessage.success(null);
    }


    @PostMapping("/ai-picture")
    @Operation(summary = "上传图片", description = "上传图片，保存到本地，返回AI理解结果")
    public ResponseMessage<AiPictureInfo> upload(@RequestParam("file") MultipartFile file) throws IOException {
        AiPictureInfo aiPictureInfo = pictureService.aiPicture(file);
        System.out.println(aiPictureInfo);
        return ResponseMessage.success(aiPictureInfo);
    }


}